home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Apple II Magazines (PO)
/
Nibble Volume 10, No. 08 (1989-08)(MindCraft Publishing)(Side A).zip
/
Nibble Volume 10, No. 08 (1989-08)(MindCraft Publishing)(Side A).po
/
PFX.S
< prev
next >
Wrap
Text File
|
1996-12-24
|
21KB
|
755 lines
********************************
* PFX *
* ProDOS Prefix Manipulator *
* by Bill Tudor *
* COPYRIGHT (C) 1988 *
* By MicroSPARC, Inc. *
* Concord, MA 01742 *
********************************
* Merlin 8/16
*-------------------------------
* PFX ia a BASIC.SYSTEM external command
* handler the adds the PFX command to the
* BASIC interpreter. This command allows
* for quick prefix manipulation without
* typing in any filenames.
*-------------------------------
* Syntax:PFX
* <no parameters>
*-------------------------------
* Machine:Any Apple II/ProDOS
* Version:1.2
* Updated:01-Jun-1988
*===============================
* Program Equates
PTR = $06 ;$06,$07
PADDR = $08 ;holds dest. addr.
PFXPTR = $1A ;$1A, $1B
DATPTR = $1C ;$1C, $1D
CURRENT = $FA ;filename to display
FNCNT = $FB ;number of filenames
ENTRY = $FC ;current directory entry
ZPTEMP1 = $FD ;temp stor.
ZPTEMP2 = $FE ;temp stor.
ZPTEMP3 = $FF ;temp stor.
* Monitor/System Equates:
CH = $24 ;40 column cursor horizontal
OPLEN = $2F ;monitor; opcode length
A1L = $3C ;monitor; MOVE start
A2L = $3E ;monitor; MOVE end
A4L = $42 ;monitor; MOVE destination
HIMEM = $73 ;current HIMEM
INBUF = $200 ;keyboard input buffer
CH2 = $57B ;cursor horizontal
KEYBD = $C000 ;the keyboard
STROBE = $C010 ;reset keyboard strobe
RD80COL = $C01F ;read 80/40 display switch
SPKR = $C030 ;produce speaker click
CHKOPLEN = $F88E ;check opcode length (NOT LABLED)
TABV = $FB5B ;set vertical cursor position
CLREOP = $FC42 ;clear from cursor down
CLREOL = $FC9C ;clear to end of line
WAIT = $FCA8 ;monitor wait routine
COUT = $FDED ;monitor character out routine
MOVE = $FE2C ;monitor MOVE
* BI Equates:
EXTRNCMD = $BE06 ;externaml command handlers
ERROUT = $BE09 ;handle an error
XTRNADDR = $BE50 ;external command address
XLEN = $BE52 ;external cmd length-1
XCNUM = $BE53 ;basic command no. (0=ext)
PBITS = $BE54 ;parameter bits allowed
FBITS = $BE56 ;found parameter bits
VPATH1 = $BE6C ;pathname buffer
GOSYSTEM = $BE70 ;execute MLI call
OSYSBUF = $BECE ;open file buffer
OREFNUM = $BED0 ;file reference #
RWREFNUM = $BED6 ;file reference #
RWDATA = $BED7 ;data buffer
RWCOUNT = $BED9 ;bytes to read
RWTRANS = $BEDB ;bytes transferred
CFREFNUM = $BEDE ;reference #
GETBUFR = $BEF5 ;allocate buffer
SUNITNUM = $BEC7 ;online unit_number
SBUFADR = $BEC8 ;online buffer
SMARK = $BEC8 ;file mark
SREFNUM = $BEC7 ;file refernece #
MACHID = $BF98 ;machine ID byte
DEVNUM = $BF30 ;last device used
* ProDOS command numbers:
On_line = $C5
Set_Prefix = $C6
Get_Prefix = $C7
Open = $C8
Read = $CA
Write = $CB
Close = $CC
Set_Mark = $CE
Get_Mark = $CF
ORG $4000 ;by convention for cmds
*===============================
* Program Installation:
*===============================
INSTALL LDA #>PEND-PSTART+$100
JSR GETBUFR ;buy space from BASIC.SYSTEM
BCC :1
JMP ERROUT ;handle the error
:1 STA PADDR ;save program new address
LDA #<STRTMSG
LDX #>STRTMSG
JSR PRTSTR ;print the string out
*===============================
* Modify the code:
*===============================
MODIFY LDA PADDR
STA MOD3+1 ;change manually
CLC
ADC #3 ;2-byte opcode fixes
STA MOD1+1 ;change manually
STA MOD2+1
*-------------------------------
LDA #<MODSTART
STA PTR ;set program pointer
LDA #>MODSTART
STA PTR+1
MODLOOP LDY #0 ;instruction byte offset
LDA (PTR),Y ;get opcode
JSR CHKOPLEN ;check opcode length
LDY OPLEN ;put length in Y
CPY #$02 ;2=3 byte instruction
BNE NOMOD ;no modification of this one
LDA (PTR),Y ;get HOB to fix
CMP #>MODSTART ;is it below our program
BLT NOMOD ;yes/no modification
CMP #>PEND+$200 ;is it above our program
BGE NOMOD ;yes/no modification
FIXIT SEC
SBC #>PSTART ;subtract min. location
CLC
ADC PADDR
STA (PTR),Y ;save the byte
NOMOD TYA ;put #bytes-1 into A
SEC ;to add 1 more
ADC PTR ;add #bytes-1+1 to PTR LOB
STA PTR ;and save
BCC CHKDNE ;see if we are done
INC PTR+1 ;fix HOB
CHKDNE LDA PTR+1 ;HOB of pointer
CMP #>MODEND ;on last page yet
BLT MODLOOP ;no, keep going
LDA PTR ;LOB of pointer
CMP #<MODEND ;are we done
BLT MODLOOP ;no, finish last page
*===============================
* Hook into BASIC.SYSTEM:
*===============================
LDA EXTRNCMD+1
STA NXTCMD+1 ;copy cuurent external command
LDA EXTRNCMD+2 ;to the next command in link
STA NXTCMD+2
LDA #0
STA EXTRNCMD+1 ;put our code address in BASIC's
LDA PADDR ;global page
STA EXTRNCMD+2
*===============================
* Move the code:
*===============================
LDA #PSTART ;start of final code
STA A1L
LDA #>PSTART
STA A1L+1 ;start adr. set
LDA #PEND ;end of final code
STA A2L
LDA #>PEND
STA A2L+1 ;end adr. set
LDA #0 ;LOB of destination
STA A4L
LDA PADDR ;HOB of destination
STA A4L+1 ;destination set
LDY #0
JSR MOVE ;execute monitor move routine
RTS ;return to BASIC
*-------------------------------
STRTMSG DFB #<EM-STRTMSG ;length
HEX 8D
ASC "PFX Command Installed.",8D8D
EM DFB #0
*-------------------------------
;installation complete
DS \ ;move to next page
*===============================
* PFX Command Handler:
*===============================
MODSTART = * ;start of modification
PSTART CLD
LDA VPATH1
STA PTR ;copy command pointer
LDA VPATH1+1
STA PTR+1
LDY #0
:LP INY
LDA (PTR),Y
CMP CMDTXT-1,Y
BNE NOTOURS ;not our command
CPY #4
BLT :LP
*===============================
* Command is ours/send to be parsed:
*===============================
PARSE DEY
DEY ;get to cmd length-1
STY XLEN ;and save it
LDA #0
STA XCNUM ;mark as external command
STA PBITS+1 ;no parms
STA PBITS
LDA #<PFXCMD
STA XTRNADDR ;tell BI where to return
MOD3 LDA #$00
STA XTRNADDR+1
CLC
RTS ;return control to BI
*
NOTOURS SEC ;flag not our command
NXTCMD JMP $0000 ;link to next command
CMDTXT ASC 'PFX',0D ;our command/note:$0D is a
;'trick' to force no parameters
*===============================
* The 'real' PFX cmd:
*===============================
PFXCMD LDA #get_prefix
JSR GOSYSTEM ;obtain current prefix
LDA VPATH1
STA PFXPTR ;set prefix pointer
LDA VPATH1+1
STA PFXPTR+1
POPLP JSR POPLEVEL ;move back a level if nesc.
PFXLP LDY #0
LDA (PFXPTR),Y ;get prefix length
CMP #2
BGE :1 ;must have a prefix
JSR GETVOLS ;get vol. names/set default
JMP DISPLAY ;display names
:1 JSR GETSUBS ;get subdirectory names
JSR FIXCUR ;determine default
*===============================
* Display Prefix and names:
*===============================
DISPLAY LDA MACHID ;check machine
LSR
LSR ;check bit 1
BCC :40 ;40-col only
BIT RD80COL ;check display
BMI :80 ;80-col display
:40 LDA #0
STA CH
LDA #22
BNE :GOV ;always taken
:80 LDA #0
STA CH2 ;80-col position
LDA #23 ;last column
:GOV JSR TABV ;position cursor
LDA #<PFXTXT
MOD1 LDX #>PFXTXT
JSR PRTSTR ;print title string
LDA PFXPTR
LDX PFXPTR+1
JSR PRTSTR ;print current prefix
JSR CLREOP ;and clear rest of scrn
*-------------------------------
* Display proper filename:
*-------------------------------
JSR SETDATPTR ;set the data pointer
LDA DATPTR
LDX DATPTR+1 ;get pointer &
JSR PRTSTR ;print the string
*-------------------------------
* Handle keypress:
*-------------------------------
NONAMES STA STROBE ;clear keyboard
NEWKEY LDA KEYBD
BPL NEWKEY ;wait for keypress
STA STROBE ;clear strobe
CMP #$9B ;is it esc?
BNE :NOESC
CLC ;flag no error
RTS ;and exit on ESC
:NOESC CMP #"\" ;backslash
BEQ BCKSLS
CMP #"<" ;or "less than"
BEQ BCKSLS
CMP #"/" ;forward slash
BEQ FORSLS
CMP #">" ;or "greater than"
BEQ FORSLS
CMP #$8D ;return pressed
BEQ RTN
CMP #$8B ;up arrow
BEQ UP
CMP #$88 ;left arrow
BEQ UP
CMP #$8A ;down arrow
BEQ DOWN
CMP #$95 ;right arrow
BEQ DOWN
CMP #$98 ;cntrl-X/clear
BEQ CNTRLX
BADINP JSR PROBELL ;ring the bell
BEQ NEWKEY ;always taken
*-------------------------------
* Handle Backslash:
*-------------------------------
BCKSLS LDY #0
LDA (PFXPTR),Y ;get current length
CMP #2 ;min.
BLT CLRPFX ;clear prefix & exit
JMP POPLP ;pop level
*-------------------------------
CLRPFX LDA #8 ;clear prefix & exit
BIT RD80COL
BMI :80
STA CH
BNE :CNT
:80 STA CH2
:CNT JSR CLREOP ;clear the screen
JMP RTN2
*-------------------------------
* Handle Forward Slash:
*-------------------------------
FORSLS JSR ADDNAME ;add current name to it
JMP PFXLP
*-------------------------------
* Handle Return:
*-------------------------------
RTN JSR ADDNAME ;add current name
RTN2 LDA #set_prefix
JSR GOSYSTEM ;set new prefix
RTS ;let BI handle errors
*-------------------------------
* Handle UP arrow:
*-------------------------------
UP DEC CURRENT
BPL TODIS
LDA FNCNT
STA CURRENT ;wrap around feature
DEC CURRENT
TODIS JMP DISPLAY ;always taken
*-------------------------------
* Handle Down Arrow:
*-------------------------------
DOWN INC CURRENT
LDA CURRENT
CMP FNCNT
BLT TODIS
LDA #0
STA CURRENT ;force current=0
BEQ TODIS ;always taken
*-------------------------------
* Handle Cntrl-X (or CLEAR):
*-------------------------------
CNTRLX LDA #0 ;just 'zero' the prefix
TAY
STA (PFXPTR),Y ;zero the length
JMP PFXLP ;always
********************************
* *
* SUBROUTINES *
* *
********************************
*===============================
* Subroutine FIXCUR:
* -Attempt to set CURRENT
* to the defualt filename
*===============================
FIXCUR LDA FNCNT
STA CURRENT
:FCLP1 DEC CURRENT
BEQ :GOTIT ;got the default
JSR SETDATPTR ;set data pointer
LDY #0
LDA (PFXPTR),Y
TAY ;move current offset
LDA #1
STA ZPTEMP1
:FCLP2 INY
LDA (PFXPTR),Y
CMP #'/'
BEQ :GOTIT
STY ZPTEMP2
LDY ZPTEMP1
CMP (DATPTR),Y
BNE :FCLP1
LDY ZPTEMP2
INC ZPTEMP1
BNE :FCLP2 ;always taken
:GOTIT RTS
*===============================
* Subroutine ADDNAME:
* - Adds CURRENT filename to the
* prefix buffer.
*===============================
ADDNAME JSR SETDATPTR ;set data pointer to cur
LDY #0
LDA (DATPTR),Y ;get data length
TAX ;counter in X
LDA (PFXPTR),Y
STA ZPTEMP1 ;offset to PFX
CLC
ADC (DATPTR),Y ;add 2 lengths
STA (PFXPTR),Y ;and save it
LDY #0
STY ZPTEMP2 ;offset to DATA
:2 INC ZPTEMP2
LDY ZPTEMP2
LDA (DATPTR),Y ;get data
INC ZPTEMP1
LDY ZPTEMP1
STA (PFXPTR),Y ;and move it
DEX
BNE :2
* Add slash, if nescessary:
LDY #0
LDA (PFXPTR),Y
TAY
LDA (PFXPTR),Y
CMP #'/' ;already there
BEQ :OK
INY
LDA #'/'
STA (PFXPTR),Y ;add the slash
TYA
LDY #0
STA (PFXPTR),Y ;and fix length
:OK RTS
*===============================
* Subroutine SETDATPTR:
* - Sets a pointer to data position
* of CURRENT filename.
*===============================
SETDATPTR LDA CURRENT ;get current filename
SETDATPTR2 STA ZPTEMP1
LDA #<MYBUF
STA DATPTR
MOD2 LDA #>MYBUF
STA DATPTR+1
LDA ZPTEMP1
BEQ :3
:2 LDA #16
CLC
ADC DATPTR
STA DATPTR
BCC :1
INC DATPTR+1
:1 DEC ZPTEMP1
BNE :2
:3 RTS
*===============================
* Subroutine GETSUBS:
* - Reads 'DIR' filenames from
* current prefix directory.
*===============================
GETSUBS LDA FNCNT
STA ZPTEMP3 ;save old names
LDY #0
STY FNCNT ;zero the count
*-------------------------------
* > Open the PFX file:
*-------------------------------
SEARCH LDA HIMEM
STA OSYSBUF
LDA HIMEM+1 ;use general-purpose buffer
STA OSYSBUF+1 ;for our I/O buffer
LDA #<INBUF
STA RWDATA ;use input buffer for data
LDA #>INBUF
STA RWDATA+1
LDA #0
STA RWCOUNT+1
STA SMARK+1
STA SMARK+2
LDA #$27
STA RWCOUNT ;entry_length = $27
CLC
ADC #4
STA SMARK ;set inital mark past header
LDA #$0C ;1 already done
STA ENTRY ;current entry
LDA #open
JSR GOSYSTEM ;open the file
BCS CHKERR ;handle error
LDA OREFNUM
STA CFREFNUM ;copy reference number
STA RWREFNUM
STA SREFNUM
LDA #Set_Mark ;must set_mark past dir
JSR GOSYSTEM ;header & bytes
BCS CHKERR
*-------------------------------
* > Check where we are in file:
*-------------------------------
CHKETRY LDA ENTRY
BNE RDENTRY
LDA #$0D ;entries_per_block
STA ENTRY
ADD4 LDA #Get_Mark
JSR GOSYSTEM
BCS CHKERR
LDA SMARK
CLC
ADC #5
STA SMARK ;save new LOB
BCC :HOBOK
INC SMARK+1 ;fix MOB
:HOBOK LDA #Set_Mark
JSR GOSYSTEM ;move over 5 bytes
BCS CHKERR
*
RDENTRY LDA #read ;read an entry
JSR GOSYSTEM
BCS CHKERR
DEC ENTRY
LDA INBUF ;stor type/name len
AND #$F0
CMP #$D0 ;check for sub
BNE CHKETRY ;go to next one
LDA INBUF
AND #$0F ;isolate length
STA INBUF ;and save
TAX
LDA FNCNT ;get current count
JSR SETDATPTR2
LDY #0
:LP LDA INBUF,Y
STA (DATPTR),Y
INY
DEX
BPL :LP
INC FNCNT ;increment file cnt
LDA FNCNT
CMP #32 ;32 files yet?
BLT CHKETRY ;next one
*-------------------------------
* > Close the file:
*-------------------------------
CLSE LDA #close ;close file
JSR GOSYSTEM
LDA FNCNT ;did we find any?
BNE :1 ;carry should be clear
JSR PROBELL ;ring the bell
LDA ZPTEMP3
STA FNCNT ;save old file cnt.
JSR POPLEVEL ;pop off a level
SEC ;flag keep current
:1 RTS
*-------------------------------
* > Check for error:
*-------------------------------
CHKERR CMP #2 ;range error
BEQ CLSE ;just close & exit
CMP #5 ;out of data (/RAM fix)
BEQ CLSE ;just close and exit
PHA ;save code
JSR CLSE ;close file
PLA
JMP ERROUT ;let BI handle it
*===============================
* Subroutine GETVOLS:
* - Use ONLINE to obtain volumes
*===============================
GETVOLS LDY #1
LDA #'/'
STA (PFXPTR),Y ;add a slash
TYA
DEY
STA (PFXPTR),Y ;1 in count byte
VOLS LDA #0
STA SUNITNUM ;scan all volumes
STA CURRENT ;zero is default
STA FNCNT ;zero the file count
LDA DEVNUM ;last device used
AND #$F0
STA ZPTEMP3 ;save for later
LDA #<INBUF
LDX #>INBUF
STA SBUFADR ;set on_line buf adr
STA PTR
STX SBUFADR+1
STX PTR+1
LDA #On_line
JSR GOSYSTEM ;make on_line call
:VOLLP LDY #0
LDA (PTR),Y ;get name len/sl/dr
BEQ VRTS ;display prefix/ect.
PHA
AND #$F0
STA ZPTEMP2
PLA
AND #$0F ;isolate name length
BEQ :NXTVOL ;bad volume, go to next
TAX
LDA FNCNT
JSR SETDATPTR2
INC FNCNT
TXA
STA (DATPTR),Y ;save corrected length
INY
:CLP LDA (PTR),Y
STA (DATPTR),Y ;copy over the filename
INY
DEX
BNE :CLP
LDA ZPTEMP3 ;last device used
CMP ZPTEMP2 ;is this default device?
BNE :NXTVOL ;no, next volume
LDA FNCNT ;fix current
STA CURRENT
DEC CURRENT
:NXTVOL LDA #16
CLC
ADC PTR
STA PTR
BCC :VOLLP
INC PTR+1
BNE :VOLLP ;always taken
VRTS CLC
RTS
*===============================
* Subroutine POPLEVEL:
*===============================
POPLEVEL LDY #0
LDA (PFXPTR),Y
BEQ :2 ;nothing to pop
TAY
:1 DEY
BEQ :2 ;trap nothing else to pop
LDA (PFXPTR),Y
CMP #'/' ;next level yet
BNE :1
:2 TYA
LDY #0
STA (PFXPTR),Y ;save new length
RTS
*===============================
* Subroutine PRTSTR:
* Prints string at (A,X).
* Converts to upper-case if II+.
*===============================
PRTSTR STA PTR
STX PTR+1 ;set pointer
LDY #0
LDA (PTR),Y ;get length
BEQ :RTS
TAX ;length in X
:LP INY
LDA (PTR),Y
ORA #$80 ;set bit 7
CMP #$E1
BLT :PRT
BIT MACHID
BMI :PRT
AND #$DF ;convert to upper if II+
:PRT JSR COUT
DEX
BNE :LP
:RTS RTS
*===============================
* Subroutine PROBELL to produce
* a beep on the speaker. This is
* Apple's ProDOS buzz.
*===============================
PROBELL LDA #$20 ;duration of tone
STA LENGTH
BELL1 LDA #$2 ;short delay click
JSR WAIT
STA SPKR
LDA #$24 ;long delay click
JSR WAIT
STA SPKR
DEC LENGTH
BNE BELL1 ;Repeat for LENGTH times
RTS
LENGTH DS 1
MODEND = * ;DO NOT MODIFY TEXT
*===============================
* Parameter Lists/Data:
*===============================
PFXTXT STR "Prefix:"
MYBUF DS 512 ;filename data buffer
*-------------------------------
PEND = * ;end of program